Selecting Images and Documents Using PhotosPicker and DocumentPicker
Course: iOS App Development
Topic: Selecting Images and Documents Using PhotosPicker and DocumentPicker
Course Link: iOS Training Course
Demo Link: Register for Course Demo
Website: JustAcademy
1. Introduction to PhotosPicker and DocumentPicker
Modern iOS applications frequently require users to select images, videos, and documents from their devices. Features such as profile picture uploads, document submissions, photo galleries, resume uploads, and file-sharing systems depend on these capabilities.
Apple provides PhotosPicker and document picker interfaces to make media and document selection easier while maintaining user privacy.
What Is PhotosPicker?
PhotosPicker is a SwiftUI component available from iOS 16 that allows users to select images and videos from their Photos library. It provides a system-managed selection interface, allowing users to share selected media without granting an application unrestricted access to their entire photo library.
What Is DocumentPicker?
DocumentPicker functionality allows users to browse and select files from locations such as iCloud Drive, local storage, and supported third-party file providers. Developers can implement it using UIDocumentPickerViewController or SwiftUI's fileImporter and fileExporter modifiers.
Difference Between PhotosPicker and DocumentPicker
| Feature |
PhotosPicker |
DocumentPicker |
| Purpose |
Select photos and videos. |
Select and manage documents. |
| Framework |
PhotosUI |
UIKit and UniformTypeIdentifiers |
| Main Component |
PhotosPicker |
UIDocumentPickerViewController |
| SwiftUI Support |
Native SwiftUI component. |
fileImporter and UIViewControllerRepresentable. |
| File Types |
Images and videos. |
PDF, DOCX, TXT, CSV, ZIP, and other files. |
| Privacy |
User-selected media access. |
User-controlled document access. |
2. Understanding the PhotosUI Framework
PhotosUI is Apple's framework for providing photo and video selection interfaces in iOS applications. It allows developers to integrate media selection without building a custom photo browser.
Important PhotosUI Components
| Component |
Description |
| PhotosPicker |
Displays the photo and video selection interface. |
| PhotosPickerItem |
Represents a selected media item. |
| PhotosPickerSelectionBehavior |
Controls selection behavior where supported. |
| Transferable |
Defines how selected content is transferred. |
| Image |
Displays loaded images in SwiftUI. |
Importing PhotosUI
import SwiftUI
import PhotosUI
3. Creating a Basic PhotosPicker
The PhotosPicker component allows users to open their photo library and select an image. The selected item is stored in a state variable.
Example: Basic Image Selection
import SwiftUI
import PhotosUI
struct ContentView: View {
@State private var selectedItem: PhotosPickerItem?
var body: some View {
VStack(spacing: 20) {
PhotosPicker(
"Select Image",
selection: $selectedItem,
matching: .images
)
Text("Choose an image from your library")
}
.padding()
}
}
Explanation:
PhotosPicker displays the system photo selection interface.
selectedItem stores the selected media item.
$selectedItem creates a binding between the picker and SwiftUI state.
matching: .images restricts selection to images.
4. Loading and Displaying Selected Images
After selecting an image, developers need to load its data into the application. PhotosPickerItem provides the loadTransferable method for asynchronously loading selected content.
Example: Loading an Image Using Data
import SwiftUI
import PhotosUI
struct ImagePickerView: View {
@State private var selectedItem: PhotosPickerItem?
@State private var selectedImage: UIImage?
var body: some View {
VStack(spacing: 20) {
PhotosPicker(
"Choose Photo",
selection: $selectedItem,
matching: .images
)
if let selectedImage {
Image(uiImage: selectedImage)
.resizable()
.scaledToFit()
.frame(height: 250)
}
}
.padding()
.onChange(of: selectedItem) {
Task {
guard let data = try? await selectedItem?
.loadTransferable(type: Data.self),
let image = UIImage(data: data) else {
selectedImage = nil
return
}
selectedImage = image
}
}
}
}
Explanation:
@State stores the selected item and loaded image.
loadTransferable(type: Data.self) loads image data.
UIImage(data:) converts image data into a UIImage.
Image(uiImage:) displays the selected image.
Task performs asynchronous image loading.
5. Selecting Multiple Images Using PhotosPicker
Some applications need users to select multiple images at once. Examples include gallery applications, social media uploads, product listing applications, and photo-sharing platforms.
Example: Multiple Image Selection
import SwiftUI
import PhotosUI
struct MultipleImagePicker: View {
@State private var selectedItems: [PhotosPickerItem] = []
var body: some View {
VStack(spacing: 20) {
PhotosPicker(
"Select Multiple Images",
selection: $selectedItems,
maxSelectionCount: 5,
matching: .images
)
Text("Selected Images: \(selectedItems.count)")
}
.padding()
}
}
Explanation:
selectedItems stores multiple selected media items.
maxSelectionCount: 5 limits the selection to five images.
matching: .images allows image selection.
- The selected item count can be displayed using Text.
6. Selecting Images and Videos
PhotosPicker supports selecting both images and videos. Developers can configure the matching parameter according to the application's requirements.
Common Selection Filters
| Filter |
Purpose |
| .images |
Selects images. |
| .videos |
Selects videos. |
| .any(of: [.images, .videos]) |
Allows images and videos. |
| .any |
Allows supported media types. |
Example: Selecting Images and Videos
import SwiftUI
import PhotosUI
struct MediaPickerView: View {
@State private var selectedMedia: PhotosPickerItem?
var body: some View {
PhotosPicker(
"Select Media",
selection: $selectedMedia,
matching: .any(of: [.images, .videos])
)
}
}
7. Understanding Transferable in SwiftUI
Transferable is a Swift protocol that defines how data can be transferred between applications and system components. PhotosPicker uses this protocol to load selected content into an application.
Developers can use built-in transferable types such as Data, Image, and URL, depending on the content and transfer requirements.
Example: Loading an Image Using Transferable
import SwiftUI
import PhotosUI
struct TransferableImagePicker: View {
@State private var selectedItem: PhotosPickerItem?
@State private var image: Image?
var body: some View {
VStack {
PhotosPicker(
"Choose Image",
selection: $selectedItem,
matching: .images
)
if let image {
image
.resizable()
.scaledToFit()
.frame(height: 250)
}
}
.onChange(of: selectedItem) {
Task {
guard let loadedImage =
try? await selectedItem?.loadTransferable(
type: Image.self
) else {
image = nil
return
}
image = loadedImage
}
}
}
}
8. Introduction to Document Picker in iOS
Document selection is an important feature in applications that work with external files. Apple's document picker allows users to access documents stored in iCloud Drive, local storage, and supported file provider applications.
Common Document Formats
- PDF files (.pdf)
- Microsoft Word documents (.doc and .docx)
- Excel spreadsheets (.xls and .xlsx)
- Text files (.txt)
- CSV files (.csv)
- ZIP archives (.zip)
- JSON files (.json)
Importing Required Frameworks
import SwiftUI
import UniformTypeIdentifiers
For UIKit-based document picker implementation, import UIKit as well.
9. Using SwiftUI fileImporter to Select Documents
SwiftUI provides the fileImporter modifier, which displays a system document selection interface. It is a convenient alternative when developers want to implement document selection without creating a custom UIKit wrapper.
Example: Selecting a PDF Document
import SwiftUI
import UniformTypeIdentifiers
struct DocumentPickerView: View {
@State private var showImporter = false
@State private var selectedFileName = "No file selected"
var body: some View {
VStack(spacing: 20) {
Button("Select PDF Document") {
showImporter = true
}
Text(selectedFileName)
}
.fileImporter(
isPresented: $showImporter,
allowedContentTypes: [.pdf],
allowsMultipleSelection: false
) { result in
switch result {
case .success(let urls):
if let url = urls.first {
selectedFileName = url.lastPathComponent
}
case .failure(let error):
print("File selection error: \(error)")
}
}
.padding()
}
}
Explanation:
fileImporter presents the system document selection interface.
isPresented controls whether the picker is displayed.
allowedContentTypes specifies accepted file formats.
allowsMultipleSelection determines whether users can select multiple files.
result returns selected file URLs or an error.
10. Selecting Multiple Documents
Applications such as document management systems and file upload tools often need multiple document selection.
Example: Multiple PDF Selection
import SwiftUI
import UniformTypeIdentifiers
struct MultipleDocumentPicker: View {
@State private var showImporter = false
@State private var selectedFiles: [URL] = []
var body: some View {
VStack(spacing: 20) {
Button("Choose Documents") {
showImporter = true
}
List(selectedFiles, id: \.self) { file in
Text(file.lastPathComponent)
}
}
.fileImporter(
isPresented: $showImporter,
allowedContentTypes: [.pdf],
allowsMultipleSelection: true
) { result in
switch result {
case .success(let urls):
selectedFiles = urls
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
11. Selecting Different File Types
Document picker functionality supports multiple file formats through Uniform Type Identifiers. Developers can define which file types are accepted by their applications.
Common UTType Values
| UTType |
File Format |
| .pdf |
PDF documents. |
| .image |
Image files. |
| .jpeg |
JPEG images. |
| .png |
PNG images. |
| .plainText |
Plain text files. |
| .spreadsheet |
Spreadsheet documents. |
| .json |
JSON files. |
| .zip |
ZIP archives. |
| .movie |
Movie files. |
Example: Selecting Images and PDFs
.fileImporter(
isPresented: $showImporter,
allowedContentTypes: [
.image,
.pdf
],
allowsMultipleSelection: true
) { result in
switch result {
case .success(let urls):
print("Selected files: \(urls.count)")
case .failure(let error):
print(error.localizedDescription)
}
}
12. Using UIDocumentPickerViewController
UIDocumentPickerViewController is the UIKit document picker component. It provides more direct control over document importing, opening, and exporting workflows.
When developing a SwiftUI application, developers can integrate this UIKit component through UIViewControllerRepresentable.
Example: Creating a UIKit Document Picker
import SwiftUI
import UIKit
import UniformTypeIdentifiers
struct DocumentPicker: UIViewControllerRepresentable {
var onPick: ([URL]) -> Void
func makeUIViewController(
context: Context
) -> UIDocumentPickerViewController {
let picker = UIDocumentPickerViewController(
forOpeningContentTypes: [.pdf, .plainText],
asCopy: true
)
picker.delegate = context.coordinator
picker.allowsMultipleSelection = true
return picker
}
func updateUIViewController(
_ uiViewController: UIDocumentPickerViewController,
context: Context
) {}
func makeCoordinator() -> Coordinator {
Coordinator(onPick: onPick)
}
class Coordinator: NSObject,
UIDocumentPickerDelegate {
var onPick: ([URL]) -> Void
init(onPick: @escaping ([URL]) -> Void) {
self.onPick = onPick
}
func documentPicker(
_ controller: UIDocumentPickerViewController,
didPickDocumentsAt urls: [URL]
) {
onPick(urls)
}
}
}
Explanation:
UIViewControllerRepresentable integrates UIKit controllers into SwiftUI.
UIDocumentPickerViewController presents the document selection interface.
forOpeningContentTypes defines supported document types.
asCopy: true requests imported copies of selected documents.
allowsMultipleSelection enables multiple document selection.
UIDocumentPickerDelegate handles document selection callbacks.
makeCoordinator() connects the picker delegate to the SwiftUI component.
13. Importing and Reading Selected Files
After selecting a document, an application may need to read its contents, upload it to a server, or save it within its own storage.
For security reasons, URLs returned by document providers may require security-scoped resource access. Developers should use the appropriate access mechanism when reading external files.
Example: Reading a Selected Text File
import Foundation
func readTextFile(from url: URL) throws -> String {
let accessed = url.startAccessingSecurityScopedResource()
defer {
if accessed {
url.stopAccessingSecurityScopedResource()
}
}
return try String(
contentsOf: url,
encoding: .utf8
)
}
Explanation:
startAccessingSecurityScopedResource() requests access to a security-scoped external file.
defer ensures cleanup occurs when the function exits.
String(contentsOf:encoding:) reads file contents as text.
stopAccessingSecurityScopedResource() releases the access permission.
14. Copying Imported Documents into Application Storage
Applications sometimes need to retain imported files for future access. Developers can copy selected documents into the application's Documents directory.
Example: Copying a Document
import Foundation
func saveDocument(from sourceURL: URL) throws -> URL {
let accessed = sourceURL
.startAccessingSecurityScopedResource()
defer {
if accessed {
sourceURL.stopAccessingSecurityScopedResource()
}
}
let fileManager = FileManager.default
let documentsDirectory = fileManager.urls(
for: .documentDirectory,
in: .userDomainMask
)[0]
let destinationURL = documentsDirectory
.appendingPathComponent(sourceURL.lastPathComponent)
if fileManager.fileExists(atPath: destinationURL.path) {
try fileManager.removeItem(at: destinationURL)
}
try fileManager.copyItem(
at: sourceURL,
to: destinationURL
)
return destinationURL
}
Important: Use appropriate security-scoped access for external document URLs. For files obtained from SwiftUI fileImporter, access them within the supported file-access scope. Avoid unnecessarily copying large files or replacing existing documents without appropriate user confirmation.
15. Understanding File Importing and Exporting
Document importing and exporting are two important file-management operations.
| Operation |
Description |
Example |
| Import |
Brings an external file into the application. |
Selecting a PDF from iCloud Drive. |
| Export |
Allows the application to provide a file to another location. |
Saving a generated report as a PDF. |
| Open |
Allows an application to work with an external document. |
Opening an existing spreadsheet. |
| Copy |
Creates an application-managed copy of a file. |
Saving an uploaded resume locally. |
16. Exporting Files Using SwiftUI fileExporter
SwiftUI provides the fileExporter modifier for exporting content from an application to a location selected by the user.
Example: Exporting a Text Document
import SwiftUI
import UniformTypeIdentifiers
struct TextDocument: FileDocument {
static var readableContentTypes: [UTType] {
[.plainText]
}
var text: String
init(text: String = "") {
self.text = text
}
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let content = String(data: data, encoding: .utf8)
else {
throw CocoaError(.fileReadCorruptFile)
}
text = content
}
func fileWrapper(
configuration: WriteConfiguration
) throws -> FileWrapper {
FileWrapper(
regularFileWithContents: Data(text.utf8)
)
}
}
struct ExportView: View {
@State private var showExporter = false
var body: some View {
Button("Export Text File") {
showExporter = true
}
.fileExporter(
isPresented: $showExporter,
document: TextDocument(
text: "Welcome to iOS Development"
),
contentType: .plainText,
defaultFilename: "MyDocument"
) { result in
switch result {
case .success(let url):
print("Exported to: \(url)")
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
This example creates a custom FileDocument type and allows users to export a text file through the system interface.
17. Handling File Selection Errors
File selection and importing can fail for several reasons, including unavailable files, unsupported formats, permission restrictions, and storage problems.
Common File Selection Errors
| Error Scenario |
Possible Cause |
Recommended Solution |
| Unsupported File |
The selected file format is not supported. |
Validate the file type. |
| Permission Error |
The application cannot access the selected resource. |
Check security-scoped access. |
| File Not Found |
The file was moved or deleted. |
Ask the user to select it again. |
| Import Failure |
The file cannot be copied or read. |
Handle the thrown error. |
| Cancelled Selection |
The user closes the picker without selecting a file. |
Keep the existing application state. |
| Storage Error |
Insufficient available storage. |
Display an appropriate message. |
Example: Error Handling
func handleDocumentSelection(
result: Result<[URL], Error>
) {
switch result {
case .success(let urls):
for url in urls {
print("Selected: \(url.lastPathComponent)")
}
case .failure(let error):
print("Selection failed: \(error.localizedDescription)")
}
}
18. Managing Image and Document Uploads
Many iOS applications allow users to upload selected images and documents to a remote server. This functionality is commonly used in registration forms, job portals, social applications, and cloud storage systems.
Typical Upload Workflow
- Display PhotosPicker or DocumentPicker.
- Allow the user to select the required file.
- Load the selected content.
- Validate file type and file size.
- Prepare the file data for uploading.
- Create an HTTP multipart request.
- Send the request to the backend server.
- Handle the server response.
- Display success or failure feedback.
Example: Uploading Image Data Using URLSession
import Foundation
func uploadImage(data: Data, to url: URL) async throws {
var request = URLRequest(url: url)
request.httpMethod = "POST"
let boundary = UUID().uuidString
request.setValue(
"multipart/form-data; boundary=\(boundary)",
forHTTPHeaderField: "Content-Type"
)
var body = Data()
body.append(Data("--\(boundary)\r\n".utf8))
body.append(
Data("Content-Disposition: form-data; name=\"file\"; filename=\"photo.jpg\"\r\n".utf8)
)
body.append(Data("Content-Type: image/jpeg\r\n\r\n".utf8))
body.append(data)
body.append(Data("\r\n--\(boundary)--\r\n".utf8))
request.httpBody = body
let (_, response) = try await URLSession.shared.data(
for: request
)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw URLError(.badServerResponse)
}
}
This example demonstrates a basic multipart upload. Production applications should also implement file size limits, authentication, upload progress, cancellation, server-side validation, and appropriate content-type handling.
19. Improving Performance and Security
Handling images and documents requires attention to performance, privacy, and storage management.
Performance Best Practices
- Load images asynchronously instead of blocking the main thread.
- Avoid loading large image files unnecessarily.
- Resize or compress images when appropriate.
- Limit the number of simultaneously selected files.
- Use background processing for expensive file operations.
- Handle upload progress and cancellation.
- Remove temporary files when they are no longer needed.
Security Best Practices
- Validate selected file extensions and actual content types.
- Never assume a file is safe based only on its extension.
- Use security-scoped resource access correctly.
- Protect confidential documents and personal images.
- Avoid storing sensitive files unnecessarily.
- Use secure HTTPS connections for uploads.
- Validate file size and content on the server.
- Request only the permissions required by the application.
20. Building a Practical Image and Document Picker Application
A useful practice project is an Image and Document Manager application. It allows users to select images from their Photos library and import documents from the Files application.
Project Features
- Select a profile image using PhotosPicker.
- Display the selected image.
- Select multiple images from the photo library.
- Import PDF and text documents.
- Display selected document names.
- Save imported documents inside application storage.
- Export generated text documents.
- Validate file formats and file sizes.
- Handle errors and cancelled selections.
Suggested Project Structure
ImageDocumentManager/
│
├── Models/
│ ├── SelectedImage.swift
│ └── DocumentItem.swift
│
├── Views/
│ ├── ContentView.swift
│ ├── PhotoPickerView.swift
│ ├── DocumentPickerView.swift
│ └── FileListView.swift
│
├── Services/
│ ├── ImageService.swift
│ ├── DocumentService.swift
│ └── UploadService.swift
│
└── Utilities/
└── FileValidator.swift
Project Development Steps
- Create a new SwiftUI project using Xcode.
- Import PhotosUI and UniformTypeIdentifiers.
- Create a PhotosPicker component.
- Load and display selected images.
- Implement multiple image selection.
- Create a document selection interface using fileImporter.
- Implement document reading and copying.
- Add file exporting functionality.
- Implement file validation and error handling.
- Test the application with different image and document formats.
21. Common Interview Questions and Answers
Q1. What is PhotosPicker in iOS?
Answer: PhotosPicker is a SwiftUI component that allows users to select images and videos from their Photos library using Apple's system-managed selection interface.
Q2. What is DocumentPicker?
Answer: DocumentPicker refers to Apple's document selection interface, commonly implemented using UIDocumentPickerViewController or SwiftUI's fileImporter modifier.
Q3. What is PhotosPickerItem?
Answer: PhotosPickerItem represents an individual media item selected through PhotosPicker. It provides methods such as loadTransferable for loading selected content.
Q4. What is Transferable?
Answer: Transferable is a Swift protocol that describes how data can be transferred between system components and applications.
Q5. What is the purpose of fileImporter?
Answer: fileImporter is a SwiftUI modifier that presents the system document picker and allows users to import files of specified content types.
Q6. What is UIDocumentPickerViewController?
Answer: It is a UIKit controller that provides document selection, opening, importing, and exporting interfaces.
Q7. What is UniformTypeIdentifiers?
Answer: UniformTypeIdentifiers is an Apple framework that provides standardized identifiers for file types such as PDF, images, text, and spreadsheets.
Q8. What is security-scoped resource access?
Answer: Security-scoped resource access allows applications to access external files through permission-controlled URLs provided by the operating system.
Q9. What is the difference between fileImporter and fileExporter?
Answer: fileImporter allows users to select and import external files, whereas fileExporter allows applications to provide files that users can save to a chosen location.
Q10. How can developers handle multiple image selection?
Answer: Developers can use an array of PhotosPickerItem values and configure maxSelectionCount to control how many images users can select.
Q11. Why should developers validate uploaded files?
Answer: File validation helps prevent unsupported formats, excessively large uploads, malformed files, and potentially unsafe content from entering an application.
Q12. Why is asynchronous image loading important?
Answer: Asynchronous loading prevents expensive image operations from blocking the main user interface and improves application responsiveness.
22. Practical Exercises
- Create a SwiftUI screen containing a basic PhotosPicker.
- Select an image and display it inside an Image component.
- Implement multiple image selection with a maximum limit of five images.
- Allow users to select both images and videos.
- Build a PDF document importer using fileImporter.
- Implement multiple PDF document selection.
- Create a custom UIKit document picker using UIViewControllerRepresentable.
- Read the contents of a selected text file.
- Copy an imported document into application storage.
- Build a text document exporter using fileExporter.
- Implement file type and file size validation.
- Create a complete Image and Document Manager application.
23. Quick Revision Checklist
- Understand PhotosPicker and DocumentPicker.
- Know the difference between PhotosUI and UniformTypeIdentifiers.
- Import the required Swift frameworks.
- Create a basic PhotosPicker interface.
- Load selected images using loadTransferable.
- Display selected images using SwiftUI Image.
- Implement multiple image and video selection.
- Understand the Transferable protocol.
- Use fileImporter to select documents.
- Understand UIDocumentPickerViewController.
- Work with PDF, TXT, JSON, and image file formats.
- Understand security-scoped resource access.
- Read and copy imported documents.
- Export files using fileExporter.
- Handle file selection errors.
- Validate file types and file sizes.
- Implement secure file uploads.
Conclusion
Selecting images and documents using PhotosPicker and DocumentPicker is an essential skill in modern iOS application development. PhotosPicker provides a convenient way to select images and videos, while document picker functionality allows applications to import and export files from supported storage locations.
By combining SwiftUI, PhotosUI, UIKit, UniformTypeIdentifiers, and Transferable, developers can create flexible file-management features while maintaining user privacy and application security.
Practical experience with image selection, multiple file importing, document exporting, file validation, and secure uploads prepares developers to build real-world iOS applications.
Explore iOS App Development Training
Learn Swift programming, SwiftUI, UIKit, image handling, document management, API integration, Firebase, and practical iOS application development through structured training at JustAcademy.
Course: Explore iOS App Development Course
Free Demo: Register for a Free Demo Class
JustAcademy Website: Visit JustAcademy